﻿/*
 				________________________________COPYRIGHT_______________________________________
				Die Veröffentlichung dieses Objektes ist Illegal und wird strafrechtlich verfolgt
				werden. Sollte es zu einer Veröffentlichung kommen werden wir die Daten des
				Herrausgebers fündig machen und Anzeige erstatten. Desweiteren ist
				auch jeglicher Besitz dieses Objektes Illegal und kann ebenfalls als Grund für
				eine Anzeige verwendet werden.
				Ausnahmen der veröffentlichung und verleihung gelten nur wenn der Grundbesitzer
				diese durchführt.
				Die Uhrheberrechte dieses Objektes liegen der Entwickler Gruppe CyberScripting vor. 
                © 2011.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace cubeworld
{
    public class CubeModel
    {
        private static VertexBuffer _vertexBuffer;
        public static VertexBuffer VertexBuffer
        {
            get
            {
                if (_vertexBuffer != null)
                    return _vertexBuffer;
                else
                {
                    List<VertexPositionNormalTexture> list = new List<VertexPositionNormalTexture>();

                    #region vertices
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 1, 1), new Vector3(-1, +1, +1), new Vector2(0, 0)));    // 0
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(+1, +1, +1), new Vector2(1, 0)));    // 1
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 0, 1), new Vector3(-1, -1, +1), new Vector2(0, 1)));    // 2
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(+1, +1, +1), new Vector2(1, 0)));    // 3
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 0, 1), new Vector3(+1, -1, +1), new Vector2(1, 1)));    // 4
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 0), new Vector3(+1, +1, -1), new Vector2(0, 0)));    // 5
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 1, 0), new Vector3(-1, +1, -1), new Vector2(1, 0)));    // 6
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 0, 0), new Vector3(-1, -1, -1), new Vector2(1, 1)));    // 7
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 0, 0), new Vector3(+1, +1, -1), new Vector2(0, 1)));    // 8
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 1, 0), new Vector3(-1, +1, +1), new Vector2(0, 0)));    // 9
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 1, 1), new Vector3(-1, +1, -1), new Vector2(1, 0)));    // 10
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 0, 0), new Vector3(-1, -1, -1), new Vector2(0, 1)));    // 11
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 0, 1), new Vector3(-1, -1, +1), new Vector2(1, 1)));    // 12
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(+1, +1, -1), new Vector2(0, 0)));    // 13
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 0), new Vector3(+1, +1, -1), new Vector2(1, 0)));    // 14
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 0, 0), new Vector3(+1, -1, -1), new Vector2(1, 1)));    // 15
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 0, 1), new Vector3(+1, +1, +1), new Vector2(0, 1)));    // 16
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 1, 1), new Vector3(-1, +1, +1), new Vector2(0, 1)));    // 17
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(-1, +1, +1), new Vector2(1, 1)));    // 18
                    list.Add(new VertexPositionNormalTexture(new Vector3(0, 0, 1), new Vector3(-1, -1, +1), new Vector2(0, 0)));    // 19
                    list.Add(new VertexPositionNormalTexture(new Vector3(1, 0, 1), new Vector3(+1, -1, +1), new Vector2(1, 0)));    // 20
                    #endregion

                    _vertexBuffer = new VertexBuffer(MainGame.Device, typeof(VertexPositionNormalTexture), list.Count, BufferUsage.WriteOnly);
                    _vertexBuffer.SetData<VertexPositionNormalTexture>(list.ToArray());

                    return _vertexBuffer;
                }
            }
        }

        private static IndexBuffer _indexBuffer;
        public static IndexBuffer IndexBuffer
        {
            get
            {
                if (_indexBuffer != null)
                    return _indexBuffer;
                else
                {
                    List<int> list = new List<int>();

                    #region indices
                    list.Add(0);
                    list.Add(1);
                    list.Add(2);
                    list.Add(3);
                    list.Add(4);
                    list.Add(2);
                    list.Add(5);
                    list.Add(6);
                    list.Add(7);
                    list.Add(8);
                    list.Add(5);
                    list.Add(7);
                    list.Add(9);
                    list.Add(10);
                    list.Add(11);
                    list.Add(10);
                    list.Add(12);
                    list.Add(11);
                    list.Add(13);
                    list.Add(14);
                    list.Add(15);
                    list.Add(16);
                    list.Add(13);
                    list.Add(15);
                    list.Add(17);
                    list.Add(9);
                    list.Add(14);
                    list.Add(18);
                    list.Add(17);
                    list.Add(14);
                    list.Add(11);
                    list.Add(19);
                    list.Add(15);
                    list.Add(19);
                    list.Add(20);
                    list.Add(15);
                    #endregion

                    _indexBuffer = new IndexBuffer(MainGame.Device, typeof(int), list.Count, BufferUsage.WriteOnly);
                    _indexBuffer.SetData<int>(list.ToArray());

                    return _indexBuffer;
                }
            }
        }

        private static VertexDeclaration _declarationMatrix;
        public static VertexDeclaration VertexDeclarationMatrix
        {
            get 
            {
                if (_declarationMatrix != null)
                    return _declarationMatrix;

                _declarationMatrix = new VertexDeclaration(
                        new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0),
                        new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 1),
                        new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 2),
                        new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 3)
                    );

                return _declarationMatrix;
            }
        }

        private static VertexDeclaration _declarationTexture;
        public static VertexDeclaration VertexDeclarationTextureID
        {
            get
            {
                if (_declarationTexture != null)
                    return _declarationTexture;

                _declarationTexture = new VertexDeclaration(
                        new VertexElement(0, VertexElementFormat.Byte4, VertexElementUsage.Fog, 0)
                    );

                return _declarationTexture;
            }
        }


        private GraphicsDevice _device;
        private BasicEffect _effect;
        private bool _isStarted;
        public bool IsStarted
        {
            get { return _isStarted; }
        }
        private List<Matrix> matrices = new List<Matrix>();
        private List<int> textureIds = new List<int>();
        private VertexBuffer matrixBuffer;
        private VertexBuffer textureIdBuffer;

        public CubeModel()
        {
            this._device = MainGame.Device;
            this._effect = new BasicEffect(_device);
            this._effect.TextureEnabled = true;
        }


        public void BeginDraw()
        {
            _isStarted = true;

            matrices.Clear();
            textureIds.Clear();
        }

        public void DrawCubeModel(Vector3 position, int textureId)
        {
            if (!_isStarted)
                throw new Exception("BeginDraw() have to be called first.");

            matrices.Add(Matrix.CreateTranslation(position));
            textureIds.Add(textureId);
        }

        public void EndDraw()
        {
            _isStarted = false;

            if (matrices.Count <= 0)
                return;

            Data.instancedEffect.Parameters["View"].SetValue(Data.camera.View);
            Data.instancedEffect.Parameters["Projection"].SetValue(Data.camera.Projection);
            Data.instancedEffect.Parameters["World"].SetValue(Matrix.Identity);

            if (matrixBuffer == null || matrixBuffer.VertexCount < matrices.Count)
            {
                if (matrixBuffer != null)
                    matrixBuffer.Dispose();

                matrixBuffer = new VertexBuffer(MainGame.Device, VertexDeclarationMatrix, matrices.Count, BufferUsage.WriteOnly);
            }
            if (textureIdBuffer == null || textureIdBuffer.VertexCount < textureIds.Count)
            {
                if (textureIdBuffer != null)
                    textureIdBuffer.Dispose();

                textureIdBuffer = new VertexBuffer(MainGame.Device, VertexDeclarationTextureID, textureIds.Count, BufferUsage.WriteOnly);
            }

            matrixBuffer.SetData(matrices.ToArray(), 0, matrices.Count);
            textureIdBuffer.SetData(textureIds.ToArray());

            MainGame.Device.SetVertexBuffers(new VertexBufferBinding(VertexBuffer, 0, 0), 
                new VertexBufferBinding(matrixBuffer, 0, 1),
                new VertexBufferBinding(textureIdBuffer, 0, 1));
            MainGame.Device.Indices = IndexBuffer;

            foreach (EffectPass pass in Data.instancedEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                MainGame.Device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 21, 0, 12, matrices.Count);
            }
        }
    }
}
